﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace FierceWar
{
	public enum ModelType
	{
		Banner,
		Barrel1,
		Barrel2,
		Barrel3,
		Barrel4,
		Barrel5,
		Barrel6,
		Barrel7,
		Barrel8,
		Barrel9,
		Barrel10,
		Bradley,
		Buggy,
		Carriage,
		Crate,
		Dog,
		EuroFighter,
		Fence,
		Grass,
		Ground,
		Harpoon,
		Helicopter,
		Horse,
		House1,
		House2,
		House3,
		House4,
		House5,
		House6,
		House7,
		House8,
		House9,
		Mig_35,
		Road,
		Shockwave,
		Skeleton,
		Stone_Normal,
		Stone_Special,
		StreetSign,
		Tower,
		Tree1_Green,
		Tree1_White,
		Tree2_Black,
		Tree2_Green,
		Wall1_Full,
		Wall1_Middle,
		Wall1_OneSide,
		Wall1_Standard,
		Wall2_Full,
		Wall2_Middle,
		Wall2_OneSide,
		Wall2_Standard,
		Wall3_Full,
		Wall3_OneSide,
		Wall3_Standard,
		Wall4,
		Wall5,
		Wall6,
        Ship1,
        Ship2,
        Ship3,
        Ship4,
        Ship5,
        Ship6,
        Ship7,
        Ship8,
        Ship9,
		Bullet,
	}

    public class ElementalModel
    {
		#region Fields.
		// Position of the model.
		private bool _isColored = false;
		public Color Color
		{
			set
			{
				_isColored = true;
				foreach (ModelMesh mesh in Model.Meshes)
				{
					foreach (BasicEffect effect in mesh.Effects)
					{
						effect.AmbientLightColor = value.ToVector3();
					}
				}
			}
		}

		private Vector3 _position = Vector3.Zero;
		public Vector3 Position
		{
			get
			{
				return _position;
			}
			set
			{
				_position = value;
			}
		}

		// Rotation vector.
		public Vector3 Rotation = Vector3.Zero;

		// Scale vector.
		public Vector3 Scale = new Vector3(1.0f);

		// My model.
		public Model Model { get; private set; }
		public ModelType Type;

		// Absolute bone transforms.
		private Matrix[] _modelTransforms;

		// World matrix.
		private Matrix _world;
		public Matrix World
		{
			get
			{
				return _world;
			}
		}

		public List<int> BoundingBoxMasterIndexes = new List<int>();

		// Bounding box.
		private Vector3[] _vertices = new Vector3[8];
		public BoundingBox BoundingBox
		{
			get
			{
				UpdateWorldMatrix();

				Vector3[] vertices = new Vector3[8];
				for (int i = 0; i < 8; i++)
				{
					vertices[i] = Vector3.Transform(_vertices[i], _world);
				}

				return BoundingBox.CreateFromPoints(vertices);
			}
		}

		// Oriented bounding box.
		public OrientedBoundingBox OrientedBoundingBox;

		// The model has placed yet ?
		public bool IsPlaced = false;

		// The model is allowed to place ?
		// false if collision occurs.
		public bool EnablePlaced = true; 
		#endregion

		public ElementalModel(ContentManager content, ModelType modelType)
        {
			Type = modelType;
			switch (Type)
			{
				case ModelType.Banner:
					{
						Scale = new Vector3(2.0f);
						LoadModel(content, "Model/Banner/Banner");
						break;
					}
				case ModelType.Barrel1:
					{
						Scale = new Vector3(200.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel1");
						break;
					}
				case ModelType.Barrel2:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel2");
						break;
					}
				case ModelType.Barrel3:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel3");
						break;
					}
				case ModelType.Barrel4:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel4");
						break;
					}
				case ModelType.Barrel5:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel5");
						break;
					}
				case ModelType.Barrel6:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel6");
						break;
					}
				case ModelType.Barrel7:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel7");
						break;
					}
				case ModelType.Barrel8:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel8");
						break;
					}
				case ModelType.Barrel9:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel9");
						break;
					}
				case ModelType.Barrel10:
					{
						Scale = new Vector3(4.0f);
						LoadModel(content, "Model/Barrel/Barrel/Barrel10");
						break;
					}
				case ModelType.Bradley:
					{
						Scale = new Vector3(1400.0f);
						LoadModel(content, "Model/Tank/Bradley");
						break;
					}
				case ModelType.Buggy:
					{
						Scale = new Vector3(0.35f);
						LoadModel(content, "Model/Car/buggy");
						break;
					}
				case ModelType.Bullet:
					{
						Scale = new Vector3(2.0f);
						LoadModel(content, "Model/Bullet/Bullet");
						break;
					}
				case ModelType.Carriage:
					{
						Scale = new Vector3(12.0f);
						LoadModel(content, "Model/Car/Carriage");
						break;
					}
				case ModelType.Crate:
					{
						Scale = new Vector3(0.15f);
						LoadModel(content, "Model/Barrel/Crate/Crate");
						break;
					}
				case ModelType.Dog:
					{
						LoadModel(content, "Model/Animal/Dog");
						break;
					}
				case ModelType.EuroFighter:
					{
						Scale = new Vector3(70.0f);
						LoadModel(content, "Model/Plane/EuroFighter");
						break;
					}
				case ModelType.Fence:
					{
						Scale = new Vector3(8.0f);
						LoadModel(content, "Model/Fence/Fence/Fence");
						break;
					}
				case ModelType.Grass:
					{
						Scale = new Vector3(20.0f);
						LoadModel(content, "Model/Plant/Grass/Grass");
						break;
					}
				case ModelType.Ground:
					{
						Scale = new Vector3(6.5536f, 0.000001f, 6.5536f);
						LoadModel(content, "Model/Ground/Ground");
						IsPlaced = true;
						break;
					}
				case ModelType.Harpoon:
					{
						Scale = new Vector3(20.0f);
						LoadModel(content, "Model/Rocket/Harpoon");
						break;
					}
				case ModelType.Helicopter:
					{
						Scale = new Vector3(220.0f);
						LoadModel(content, "Model/Plane/Helicopter");
						break;
					}
				case ModelType.Horse:
					{
						Scale = new Vector3(125.0f);
						LoadModel(content, "Model/Animal/Horse");
						break;
					}
				case ModelType.House1:
					{
						Scale = new Vector3(2.5f);
						LoadModel(content, "Model/House/House/House1");
						break;
					}
				case ModelType.House2:
					{
						LoadModel(content, "Model/House/House/House2");
						break;
					}
				case ModelType.House3:
					{
						Scale = new Vector3(5.0f);
						LoadModel(content, "Model/House/House/House3");
						break;
					}
				case ModelType.House4:
					{
						Scale = new Vector3(75.0f);
						LoadModel(content, "Model/House/House/House4");
						break;
					}
				case ModelType.House5:
					{
						Scale = new Vector3(3.0f);
						LoadModel(content, "Model/House/House/House5");
						break;
					}
				case ModelType.House6:
					{
						Scale = new Vector3(100.0f);
						LoadModel(content, "Model/House/House/House6");
						break;
					}
				case ModelType.House7:
					{
						Scale = new Vector3(9.0f);
						LoadModel(content, "Model/House/House/House7");
						break;
					}
				case ModelType.House8:
					{
						Scale = new Vector3(40.0f);
						LoadModel(content, "Model/House/House/House8");
						break;
					}
				case ModelType.House9:
					{
						Scale = new Vector3(40.0f);
						LoadModel(content, "Model/House/House/House9");
						break;
					}
				case ModelType.Mig_35:
					{
						Scale = new Vector3(25.0f);
						LoadModel(content, "Model/Plane/Mig-35");
						break;
					}
				case ModelType.Road:
					{
						LoadModel(content, "Model/Road/Road");
						break;
					}
				case ModelType.Shockwave:
					{
						Scale = new Vector3(120.0f);
						LoadModel(content, "Model/Rocket/Shockwave");
						break;
					}
				case ModelType.Skeleton:
					{
						Scale = new Vector3(2.0f);
						LoadModel(content, "Model/Skeleton/Skeleton");
						break;
					}
				case ModelType.Stone_Normal:
					{
						Scale = new Vector3(120.0f);
						LoadModel(content, "Model/Stone/Stone_norm");
						break;
					}
				case ModelType.Stone_Special:
					{
						Scale = new Vector3(120.0f);
						LoadModel(content, "Model/Stone/Stone_spec");
						break;
					}
				case ModelType.StreetSign:
					{
						Scale = new Vector3(3.0f);
						LoadModel(content, "Model/StreetSign/StreetSign");
						break;
					}
				case ModelType.Tower:
					{
						Scale = new Vector3(3.0f);
						LoadModel(content, "Model/House/Tower/Tower");
						break;
					}
				case ModelType.Tree1_Green:
					{
						Scale = new Vector3(200.0f);
						LoadModel(content, "Model/Plant/Tree/Tree1_Green");
						break;
					}
				case ModelType.Tree1_White:
					{
						Scale = new Vector3(200.0f);
						LoadModel(content, "Model/Plant/Tree/Tree1_White");
						break;
					}
				case ModelType.Tree2_Black:
					{
						Rotation = new Vector3(-MathHelper.PiOver2, 0.0f, 0.0f);
						Scale = new Vector3(70.0f);
						LoadModel(content, "Model/Plant/Tree/Tree2_Black");
						break;
					}
				case ModelType.Tree2_Green:
					{
						Rotation = new Vector3(-MathHelper.PiOver2, 0.0f, 0.0f);
						Scale = new Vector3(70.0f);
						LoadModel(content, "Model/Plant/Tree/Tree2_Green");
						break;
					}
				case ModelType.Wall1_Full:
					{
						Scale = new Vector3(15.0f);
						LoadModel(content, "Model/Fence/Wall/Wall1_Full");
						break;
					}
				case ModelType.Wall1_Middle:
					{
						Scale = new Vector3(15.0f);
						LoadModel(content, "Model/Fence/Wall/Wall1_Middle");
						break;
					}
				case ModelType.Wall1_OneSide:
					{
						Scale = new Vector3(15.0f);
						LoadModel(content, "Model/Fence/Wall/Wall1_OneSide");
						break;
					}
				case ModelType.Wall1_Standard:
					{
						Scale = new Vector3(15.0f);
						LoadModel(content, "Model/Fence/Wall/Wall1_Standard");
						break;
					}
				case ModelType.Wall2_Full:
					{
						Scale = new Vector3(10.0f);
						LoadModel(content, "Model/Fence/Wall/Wall2_Full");
						break;
					}
				case ModelType.Wall2_Middle:
					{
						Scale = new Vector3(10.0f);
						LoadModel(content, "Model/Fence/Wall/Wall2_Middle");
						break;
					}
				case ModelType.Wall2_OneSide:
					{
						Scale = new Vector3(10.0f);
						LoadModel(content, "Model/Fence/Wall/Wall2_OneSide");
						break;
					}
				case ModelType.Wall2_Standard:
					{
						Scale = new Vector3(10.0f);
						LoadModel(content, "Model/Fence/Wall/Wall2_Standard");
						break;
					}
				case ModelType.Wall3_Full:
					{
						Scale = new Vector3(12.0f);
						LoadModel(content, "Model/Fence/Wall/Wall3_Full");
						break;
					}
				case ModelType.Wall3_OneSide:
					{
						Scale = new Vector3(12.0f);
						LoadModel(content, "Model/Fence/Wall/Wall3_OneSide");
						break;
					}
				case ModelType.Wall3_Standard:
					{
						Scale = new Vector3(12.0f);
						LoadModel(content, "Model/Fence/Wall/Wall3_Standard");
						break;
					}
				case ModelType.Wall4:
					{
						Scale = new Vector3(10.0f);
						LoadModel(content, "Model/Fence/Wall/Wall4");
						break;
					}
				case ModelType.Wall5:
					{
						Scale = new Vector3(10.0f);
						LoadModel(content, "Model/Fence/Wall/Wall5");
						break;
					}
				case ModelType.Wall6:
					{
						Scale = new Vector3(5.0f);
						LoadModel(content, "Model/Fence/Wall/Wall6");
						break;
					}
                case ModelType.Ship1:
                    {
                        Scale = new Vector3(0.5f);
                        LoadModel(content, "Model/Ship/Ship1");
                        break;
                    }
                case ModelType.Ship2:
                    {
                        Scale = new Vector3(4.0f);
                        LoadModel(content, "Model/Ship/Ship2");
                        break;
                    }
                case ModelType.Ship3:
                    {
						Scale = new Vector3(3.0f);
                        LoadModel(content, "Model/Ship/Ship3");
						break;
                    }
                case ModelType.Ship4:
                    {
                        Scale = new Vector3(15.0f);
                        LoadModel(content, "Model/Ship/Ship4");
                        break;
                    }
                case ModelType.Ship5:
                    {
                        Scale = new Vector3(15.0f);
                        LoadModel(content, "Model/Ship/Ship5");
                        break;
                    }
                case ModelType.Ship6:
                    {
                        Scale = new Vector3(15.0f);
                        LoadModel(content, "Model/Ship/Ship6");
                        break;
                    }
                case ModelType.Ship7:
                    {
                        Scale = new Vector3(15.0f);
                        LoadModel(content, "Model/Ship/Ship7");
                        break;
                    }
                case ModelType.Ship8:
                    {
                        Scale = new Vector3(15.0f);
                        LoadModel(content, "Model/Ship/Ship8");
                        break;
                    }
                case ModelType.Ship9:
                    {
                        Scale = new Vector3(15.0f);
                        LoadModel(content, "Model/Ship/Ship9");
                        break;
                    }
			}

			UpdateWorldMatrix();
        }

		private void LoadModel(ContentManager content, string path)
		{
			Model = content.Load<Model>(path);

			_modelTransforms = new Matrix[Model.Bones.Count];
			Model.CopyAbsoluteBoneTransformsTo(_modelTransforms);
			
			CalculateCorners();
		}

		private void CalculateCorners()
		{
			Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
			Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);

			foreach (ModelMesh mesh in Model.Meshes)
			{
				Matrix transform = _modelTransforms[mesh.ParentBone.Index];

				foreach (ModelMeshPart meshPart in mesh.MeshParts)
				{
					int stride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
					int numberv = meshPart.NumVertices;
					byte[] vertexData = new byte[stride * numberv];

					meshPart.VertexBuffer.GetData<byte>(vertexData);

					for (int ndx = 0; ndx < vertexData.Length; ndx += stride)
					{
						float floatvaluex = BitConverter.ToSingle(vertexData, ndx);
						float floatvaluey = BitConverter.ToSingle(vertexData, ndx + 4);
						float floatvaluez = BitConverter.ToSingle(vertexData, ndx + 8);
						Vector3 vectCurrentVertex = new Vector3(floatvaluex, floatvaluey, floatvaluez);
						Vector3 vectWorldVertex = Vector3.Transform(vectCurrentVertex, transform);

						if (vectWorldVertex.X < min.X) min.X = vectWorldVertex.X;
						if (vectWorldVertex.X > max.X) max.X = vectWorldVertex.X;
						if (vectWorldVertex.Y < min.Y) min.Y = vectWorldVertex.Y;
						if (vectWorldVertex.Y > max.Y) max.Y = vectWorldVertex.Y;
						if (vectWorldVertex.Z < min.Z) min.Z = vectWorldVertex.Z;
						if (vectWorldVertex.Z > max.Z) max.Z = vectWorldVertex.Z;
					}
				}
			}

			if (Type == ModelType.EuroFighter)
			{
				min.Z = -20.0f;
			}

			_vertices = (new BoundingBox(min, max)).GetCorners();

			UpdateWorldMatrix();

			min = Vector3.Transform(min, _world);
			max = Vector3.Transform(max, _world);
			OrientedBoundingBox = new OrientedBoundingBox(min, max);
		}

		private void UpdateWorldMatrix()
		{
			_world = Matrix.CreateScale(Scale) *
				Matrix.CreateFromYawPitchRoll(
					Rotation.Y, Rotation.X, Rotation.Z) *
				Matrix.CreateTranslation(Position);
		}

        public void Draw(Matrix View, Matrix Projection, Vector3 CameraPosition)
        {
            // Calculate the base transformation by combining
            // translation, rotation, and scaling
			UpdateWorldMatrix();
			OrientedBoundingBox.Transforms =
				Matrix.CreateFromYawPitchRoll(
					Rotation.Y, Rotation.X, Rotation.Z) *
				Matrix.CreateTranslation(Position);

            foreach (ModelMesh mesh in Model.Meshes)
            {
                Matrix localWorld =
					_modelTransforms[mesh.ParentBone.Index] * _world;

				foreach (BasicEffect effect in mesh.Effects)
				{
					effect.World = localWorld;
					effect.View = View;
					effect.Projection = Projection;
					if ((Type == ModelType.Wall6) ||
						(Type == ModelType.EuroFighter) ||
						(Type == ModelType.Harpoon) ||
						(Type == ModelType.Dog) ||
						(Type == ModelType.Skeleton) ||
						(Type == ModelType.Mig_35) ||
						(Type == ModelType.Shockwave) ||
						(Type == ModelType.Bullet) ||
						(Type == ModelType.Tree1_Green) ||
						(Type == ModelType.Tree1_White) ||
						(Type == ModelType.Tree2_Black) ||
						(Type == ModelType.Tree2_Green) ||
						(Type == ModelType.Grass))
					{
						effect.EnableDefaultLighting();
					}
					effect.LightingEnabled = _isColored;
				}

                mesh.Draw();
            }
        }
    }
}
